package com.fulu.game.bi.service.impl.market;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.fulu.game.bi.common.exception.BizException;
import com.fulu.game.bi.common.util.csv.CsvExportUtil;
import com.fulu.game.bi.common.util.csv.Mapper;
import com.fulu.game.bi.common.util.csv.Querier;
import com.fulu.game.bi.entity.enums.OsEnum;
import com.fulu.game.bi.entity.enums.QueryTypeStatusEnum;
import com.fulu.game.bi.entity.po.channel.Label;
import com.fulu.game.bi.entity.po.channel.RegistSource;
import com.fulu.game.bi.entity.po.roi.NewRangePayStat;
import com.fulu.game.bi.entity.vo.market.NewRangePayQueryVO;
import com.fulu.game.bi.mysql.bi.channel.LabelGroupDao;
import com.fulu.game.bi.mysql.bi.channel.RegisterSourceGroupDao;
import com.fulu.game.bi.mysql.bi.market.NewRangePayStatDao;
import com.fulu.game.bi.mysql.playadmin.channel.LabelDao;
import com.fulu.game.bi.mysql.playadmin.channel.RegistSourceDao;
import com.fulu.game.bi.redis.service.market.NewRangePayService;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class NewRangePayServiceImpl implements NewRangePayService {

    private static final String PLACEHOLDER = "/";

    @Autowired
    private NewRangePayStatDao newAddUserStatDao;

    @Autowired
    private RegistSourceDao registSourceDao;
    @Autowired
    private RegisterSourceGroupDao registerSourceGroupDao;
    @Autowired
    private LabelDao labelDao;
    @Autowired
    private LabelGroupDao labelGroupDao;


    public static final Map<Integer, String> tableNameMap = new HashMap();

    static {
        tableNameMap.put(QueryTypeStatusEnum.DAY.getType(), "t_new_range_pay_stat_day");
        tableNameMap.put(QueryTypeStatusEnum.WEEK.getType(), "t_new_range_pay_stat_week");
        tableNameMap.put(QueryTypeStatusEnum.MONTH.getType(), "t_new_range_pay_stat_month");

    }

    protected void setEndDateStr(NewRangePayQueryVO vo, NewRangePayStat v) {
        if (QueryTypeStatusEnum.WEEK.getType().equals(vo.getQueryType())) {
            DateTime startTime = DateUtil.parse(v.getStatDate());
            DateTime endDateTime = DateUtil.offsetDay(startTime, 6);

            String statDateEnd = DateUtil.format(endDateTime, "yyyy-MM-dd");
            v.setEndStatDay(statDateEnd);
        } else {
            v.setEndStatDay(v.getStatDate());
        }
    }


    @Override
    public List<NewRangePayStat> list(NewRangePayQueryVO vo) {

        // 装配渠道
        String registerSourceGroupName = PLACEHOLDER;
        if (Objects.nonNull(vo.getRegisterSourceGroupId()) && CollectionUtil.isEmpty(vo.getRegisterSourceIdList())) {
            List<Integer> sourceIdList = registerSourceGroupDao.listItem(vo.getRegisterSourceGroupId());
            if (CollectionUtil.isEmpty(sourceIdList)) {
                return new ArrayList<>();
            }
            registerSourceGroupName = registerSourceGroupDao.findNameById(vo.getRegisterSourceGroupId());

            vo.setRegisterSourceIdList(sourceIdList);
        }

        Map<Integer, String> sourceMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(vo.getRegisterSourceIdList())) {
            List<RegistSource> sourceList = registSourceDao.findByIds(vo.getRegisterSourceIdList()).stream()
                    .collect(Collectors.toList());
            List<Integer> platforms = sourceList.stream().map(RegistSource::getPlatform).collect(Collectors.toList());
            vo.setRegisterSourceIdList(platforms);
            sourceMap = sourceList.stream().collect(Collectors.toMap(RegistSource::getPlatform, RegistSource::getName));
        }

        // 装配标签
        String labelGroupName = PLACEHOLDER;
        if (Objects.nonNull(vo.getLabelGroupId()) && CollectionUtil.isEmpty(vo.getLabelIdList())) {
            List<Integer> labelIdList = labelGroupDao.listItem(vo.getLabelGroupId());
            if (CollectionUtil.isEmpty(labelIdList)) {
                return new ArrayList<>();
            }
            labelGroupName = labelGroupDao.findNameById(vo.getLabelGroupId());

            vo.setLabelIdList(labelIdList);
        }

        Map<Integer, String> labelMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(vo.getLabelIdList())) {
            labelMap = labelDao.findByIds(vo.getLabelIdList()).stream().collect(Collectors.toMap(Label::getId, Label::getName));
        }

        String registerTypeName = PLACEHOLDER;
        if (Objects.nonNull(vo.getRegisterType())) {
            registerTypeName = OsEnum.parse(vo.getRegisterType()).getMsg();
        }
        String tableName = tableNameMap.get(vo.getQueryType());
        Optional.ofNullable(tableName).orElseThrow(() -> new BizException("不支持的查询类型"));

        List<NewRangePayStat> list = newAddUserStatDao.list(vo, tableName);
        if (vo.isExportLabel()) {
            labelMap = labelDao.findByIds(list.stream().filter(map -> map.getLabelId() != null).map(map -> map.getLabelId()).collect(Collectors.toList())).stream().collect(Collectors.toMap(Label::getId, Label::getName));
        }
        if (vo.isExportSourceId()) {
            List<RegistSource> sourceList = registSourceDao.findByPlatforms(list.stream().filter(map -> map.getSourceId() != null).map(map -> map.getSourceId()).toArray(Integer[]::new));
            sourceMap = sourceList.stream().collect(Collectors.toMap(RegistSource::getPlatform, RegistSource::getName));
        }
        // 赋值、分组
        String finalRegisterSourceGroupName = registerSourceGroupName;
        String finalLabelGroupName = labelGroupName;
        String finalRegisterTypeName = registerTypeName;
        Map<Integer, String> finalSourceMap = sourceMap;
        Map<Integer, String> finalLabelMap = labelMap;
        return list.stream()
                .peek(v -> v.setSourceGroupName(finalRegisterSourceGroupName))
                .peek(v -> v.setLabelGroupName(finalLabelGroupName))
                .peek(v -> {
                    if (v.getRegisterType() != null && vo.isExportRegisterType()) {
                        v.setRegisterTypeName(OsEnum.parse(v.getRegisterType()).getMsg());
                    } else {
                        v.setRegisterTypeName(finalRegisterTypeName);
                    }
                })
                .peek(v -> setEndDateStr(vo, v))
                .peek(v -> v.setBeginStatDay(v.getStatDate()))
                .peek(v -> {
                    if (CollectionUtil.isEmpty(vo.getRegisterSourceIdList()) && !vo.isExportSourceId()) {
                        v.setSourceName(PLACEHOLDER);
                    } else {
                        v.setSourceName(Optional.ofNullable(finalSourceMap.get(v.getSourceId())).orElse(""));
                    }
                })
                .peek(v -> {
                    if (CollectionUtil.isEmpty(vo.getLabelIdList()) && !vo.isExportLabel()) {
                        v.setLabelName(PLACEHOLDER);
                    } else {
                        v.setLabelName(Optional.ofNullable(finalLabelMap.get(v.getLabelId())).orElse(""));
                    }
                })
                .peek(v -> v.setSourceId(v.getSourceId() == null ? 0 : v.getSourceId()))
                .sorted(Comparator.comparing(NewRangePayStat::getStatDate).reversed().thenComparing(NewRangePayStat::getSourceId))
                .collect(Collectors.toList());
    }

    @Override
    public void export(NewRangePayQueryVO vo) {
        QueryTypeStatusEnum anEnum = QueryTypeStatusEnum.getEnum(vo.getQueryType());
        String site = anEnum.getMsg();

        Map<Integer, String> statTypeMap = new HashMap<>();
        statTypeMap.put(1, "总充值");
        statTypeMap.put(2, "总消费");
        statTypeMap.put(3, "皮皮币充值");
        statTypeMap.put(4, "皮皮币消费");
        statTypeMap.put(5, "钻石充值");
        statTypeMap.put(6, "钻石充值");

        String fileName = "新增用户" + statTypeMap.get(vo.getStatType()) + vo.getStatTimeStart() + "-" + vo.getStatTimeEnd();

        LinkedHashMap<String, Mapper<NewRangePayStat>> map = new LinkedHashMap<>();
        map.put("统计时间", v -> v.getBeginStatDay() + "-" + v.getEndStatDay());
        map.put("渠道分组名称", v -> v.getSourceGroupName());
        map.put("渠道名称", v -> v.getSourceName());
        map.put("标签分组名称", v -> v.getLabelGroupName());
        map.put("标签名称", v -> v.getLabelName() + "");
        map.put("系统", v -> v.getRegisterTypeName());
        map.put("新用户数", v -> v.getNewUserNum() + "");
        map.put("类型", v -> statTypeMap.get(vo.getStatType()));
        switch (anEnum) {
            case DAY:
                map.put("1" + site + "内总充值金额", v -> v.getAllMoney1() + "");
                map.put("2" + site + "内总充值金额", v -> v.getAllMoney2() + "");
                map.put("3" + site + "内总充值金额", v -> v.getAllMoney3() + "");
                map.put("4" + site + "内总充值金额", v -> v.getAllMoney4() + "");
                map.put("5" + site + "内总充值金额", v -> v.getAllMoney5() + "");
                map.put("6" + site + "内总充值金额", v -> v.getAllMoney6() + "");
                map.put("7" + site + "内总充值金额", v -> v.getAllMoney7() + "");
                map.put("14" + site + "内总充值金额", v -> v.getAllMoney14() + "");
                map.put("30" + site + "内总充值金额", v -> v.getAllMoney30() + "");

                map.put("1" + site + "总充值人数", v -> v.getAllNum1() + "");
                map.put("2" + site + "总充值人数", v -> v.getAllNum2() + "");
                map.put("3" + site + "总充值人数", v -> v.getAllNum3() + "");
                map.put("4" + site + "总充值人数", v -> v.getAllNum4() + "");
                map.put("5" + site + "总充值人数", v -> v.getAllNum5() + "");
                map.put("6" + site + "总充值人数", v -> v.getAllNum6() + "");
                map.put("7" + site + "总充值人数", v -> v.getAllNum7() + "");
                map.put("14" + site + "总充值人数", v -> v.getAllNum14() + "");
                map.put("30" + site + "总充值人数", v -> v.getAllNum30() + "");


                map.put("1" + site + "内新增金额", v -> v.getNewMoney1() + "");
                map.put("2" + site + "内新增金额", v -> v.getNewMoney2() + "");
                map.put("3" + site + "内新增金额", v -> v.getNewMoney3() + "");
                map.put("4" + site + "内新增金额", v -> v.getNewMoney4() + "");
                map.put("5" + site + "内新增金额", v -> v.getNewMoney5() + "");
                map.put("6" + site + "内新增金额", v -> v.getNewMoney6() + "");
                map.put("7" + site + "内新增金额", v -> v.getNewMoney7() + "");
                map.put("14" + site + "内新增金额", v -> v.getNewMoney14() + "");
                map.put("30" + site + "内新增金额", v -> v.getNewMoney30() + "");

                map.put("1" + site + "内新增充值人数", v -> v.getNewNum1() + "");
                map.put("2" + site + "内新增充值人数", v -> v.getNewNum2() + "");
                map.put("3" + site + "内新增充值人数", v -> v.getNewNum3() + "");
                map.put("4" + site + "内新增充值人数", v -> v.getNewNum4() + "");
                map.put("5" + site + "内新增充值人数", v -> v.getNewNum5() + "");
                map.put("6" + site + "内新增充值人数", v -> v.getNewNum6() + "");
                map.put("7" + site + "内新增充值人数", v -> v.getNewNum7() + "");
                map.put("14" + site + "内新增充值人数", v -> v.getNewNum14() + "");
                map.put("30" + site + "内新增充值人数", v -> v.getNewNum30() + "");
                break;
            default:
                map.put("1" + site + "内总充值金额", v -> v.getAllMoney1() + "");
                map.put("2" + site + "内总充值金额", v -> v.getAllMoney2() + "");
                map.put("3" + site + "内总充值金额", v -> v.getAllMoney3() + "");
                map.put("4" + site + "内总充值金额", v -> v.getAllMoney4() + "");
                map.put("5" + site + "内总充值金额", v -> v.getAllMoney5() + "");
                map.put("6" + site + "内总充值金额", v -> v.getAllMoney6() + "");
                map.put("7" + site + "内总充值金额", v -> v.getAllMoney7() + "");
                map.put("8" + site + "内总充值金额", v -> v.getAllMoney8() + "");
                map.put("9" + site + "内总充值金额", v -> v.getAllMoney9() + "");
                map.put("10" + site + "内总充值金额", v -> v.getAllMoney10() + "");
                map.put("11" + site + "内总充值金额", v -> v.getAllMoney11() + "");
                map.put("12" + site + "内总充值金额", v -> v.getAllMoney12() + "");

                map.put("1" + site + "总充值人数", v -> v.getAllNum1() + "");
                map.put("2" + site + "总充值人数", v -> v.getAllNum2() + "");
                map.put("3" + site + "总充值人数", v -> v.getAllNum3() + "");
                map.put("4" + site + "总充值人数", v -> v.getAllNum4() + "");
                map.put("5" + site + "总充值人数", v -> v.getAllNum5() + "");
                map.put("6" + site + "总充值人数", v -> v.getAllNum6() + "");
                map.put("7" + site + "总充值人数", v -> v.getAllNum7() + "");
                map.put("8" + site + "总充值人数", v -> v.getAllNum8() + "");
                map.put("9" + site + "总充值人数", v -> v.getAllNum9() + "");
                map.put("10" + site + "总充值人数", v -> v.getAllNum10() + "");
                map.put("11" + site + "总充值人数", v -> v.getAllNum11() + "");
                map.put("12" + site + "总充值人数", v -> v.getAllNum12() + "");

                map.put("1" + site + "内新增金额", v -> v.getNewMoney1() + "");
                map.put("2" + site + "内新增金额", v -> v.getNewMoney2() + "");
                map.put("3" + site + "内新增金额", v -> v.getNewMoney3() + "");
                map.put("4" + site + "内新增金额", v -> v.getNewMoney4() + "");
                map.put("5" + site + "内新增金额", v -> v.getNewMoney5() + "");
                map.put("6" + site + "内新增金额", v -> v.getNewMoney6() + "");
                map.put("7" + site + "内新增金额", v -> v.getNewMoney7() + "");
                map.put("8" + site + "内新增金额", v -> v.getNewMoney8() + "");
                map.put("9" + site + "内新增金额", v -> v.getNewMoney9() + "");
                map.put("10" + site + "内新增金额", v -> v.getNewMoney10() + "");
                map.put("11" + site + "内新增金额", v -> v.getNewMoney11() + "");
                map.put("12" + site + "内新增金额", v -> v.getNewMoney12() + "");

                map.put("1" + site + "内新增充值人数", v -> v.getNewNum1() + "");
                map.put("2" + site + "内新增充值人数", v -> v.getNewNum2() + "");
                map.put("3" + site + "内新增充值人数", v -> v.getNewNum3() + "");
                map.put("4" + site + "内新增充值人数", v -> v.getNewNum4() + "");
                map.put("5" + site + "内新增充值人数", v -> v.getNewNum5() + "");
                map.put("6" + site + "内新增充值人数", v -> v.getNewNum6() + "");
                map.put("7" + site + "内新增充值人数", v -> v.getNewNum7() + "");
                map.put("8" + site + "内新增充值人数", v -> v.getNewNum8() + "");
                map.put("9" + site + "内新增充值人数", v -> v.getNewNum9() + "");
                map.put("10" + site + "内新增充值人数", v -> v.getNewNum10() + "");
                map.put("11" + site + "内新增充值人数", v -> v.getNewNum11() + "");
                map.put("12" + site + "内新增充值人数", v -> v.getNewNum12() + "");
                break;
        }

        Querier querier = (num) -> {
            List<NewRangePayStat> list = list(vo);
            PageInfo pageInfo = new PageInfo(list);
            pageInfo.setHasNextPage(false);
            return pageInfo;
        };

        CsvExportUtil.export(100, fileName, map, querier);
    }
}
